package com.vipisall.cloud.user.controller.manage;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSONObject;

import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * <p>默认生成1-10的10位随机集合,使用{@link SecureRandom}生成随机数
 *
 * <p>可指定生成范围 MIN_NUMBER(最小值) MAX_NUMBER(最大值)
 *
 * @author Daiyin
 * @since 2024/6/27
 **/
public class RandomNumberGenerator {
    /**
     * 刷新次数
     */
    private static int refreshNum = 0;
    /**
     * 最小值
     */
    private static int minNumber;
    private static int maxNumber;
    private static int requestNumber;
    private static Map<Integer, Object> excludeNumberMap;
    private static SecureRandom SECURE_RANDOM;

    static {
        SECURE_RANDOM = new SecureRandom();
        minNumber = 1;
        maxNumber = 10;
        requestNumber = 0;
        excludeNumberMap = null;
    }

    public RandomNumberGenerator() {
    }

//    public RandomNumberGenerator(Map<Integer, Object> excludeNumMap) {
//        this.excludeNumMap = excludeNumMap;
//    }


    //    public RandomNumberGenerator(int minNum, int maxNum) {
//        this.minNumber = minNum;
//        this.maxNumber = maxNum;
//    }
//
//    public RandomNumberGenerator(int minNum, int maxNum, Map<Integer, Object> excludeNumMap) {
//        this.minNumber = minNum;
//        this.maxNumber = maxNum;
//        this.excludeNumMap = excludeNumMap;
//    }
    public static List<Integer> generateLuckyNumbers(Map<Integer, Object> excludeNumMap) {
        excludeNumberMap = excludeNumMap;
        return getNumList();
    }

    public static List<Integer> generateLuckyNumbers(int minNum, int maxNum) {
        minNumber = minNum;
        maxNumber = maxNum;
        excludeNumberMap = null;
        requestNumber = 0;
        return getNumList();
    }

    public static List<Integer> generateLuckyNumbers(int minNum, int maxNum, int requestNum) {
        minNumber = minNum;
        maxNumber = maxNum;
        requestNumber = requestNum;
        excludeNumberMap = null;
        return getNumList();
    }

    public static List<Integer> generateLuckyNumbers(int minNum, int maxNum, Map<Integer, Object> excludeNumMap) {
        minNumber = minNum;
        maxNumber = maxNum;
        requestNumber = 0;
        excludeNumberMap = excludeNumMap;
        return getNumList();
    }

    public static List<Integer> generateLuckyNumbers(int minNum, int maxNum, int requestNum, Map<Integer, Object> excludeNumMap) {
        minNumber = minNum;
        maxNumber = maxNum;
        requestNumber = requestNum;
        excludeNumberMap = excludeNumMap;
        return getNumList();
    }

    private static List<Integer> getNumList() {
        if (requestNumber != 0) {
            if (maxNumber - minNumber + 1 < requestNumber) {
                throw new IllegalArgumentException("Range is too small to generate the requested number of unique random numbers.");
            }
            //todo
            if (CollectionUtil.isNotEmpty(excludeNumberMap) && excludeNumberMap.size() >= requestNumber) {
                throw new IndexOutOfBoundsException("excludeNumberMap size " + excludeNumberMap.size() + " out of bounds for requestNumber size " + requestNumber);
            }
        }

        Set<Integer> generatedNumbers = new HashSet<>();
        if (requestNumber != 0) {
            AtomicBoolean exclude = new AtomicBoolean(true);
            while (generatedNumbers.size() < requestNumber) {
                int randomNumber = minNumber + SECURE_RANDOM.nextInt(maxNumber - minNumber + 1);
                if (CollectionUtil.isNotEmpty(excludeNumberMap) && exclude.get()) {
                    excludeNumberMap.forEach((k, v) -> {
                        if (!((List<?>) v).contains(randomNumber)) {
                            generatedNumbers.add(randomNumber);
                            exclude.set(false);
                        }
                    });
                } else {
                    generatedNumbers.add(randomNumber);
                }
            }
        } else {
            while (generatedNumbers.size() < maxNumber - minNumber + 1) {
                int randomNumber = minNumber + SECURE_RANDOM.nextInt(maxNumber - minNumber + 1);
                generatedNumbers.add(randomNumber);
            }
        }

        // 打乱顺序，模拟随机生成结果
        ArrayList<Integer> nums = new ArrayList<>(generatedNumbers);
        shuffle(nums);
        return nums;
    }

    private static void shuffle(List<Integer> numbers) {
//        refreshNum++;
//        if (refreshNum > 1000) {
//            System.out.println("刷了1000次了，就他了吧");
//            return;
//        }
        Collections.shuffle(numbers, SECURE_RANDOM);
        if (CollectionUtil.isNotEmpty(excludeNumberMap)) {
            if (excludeNumberMap.size() > maxNumber - minNumber + 1) {
                throw new IndexOutOfBoundsException("The size of excludeNumberMap out of bounds maxNumber,excludeNumberMap must be less than maxNumber");
            }

            AtomicBoolean flag = new AtomicBoolean(false);
            excludeNumberMap.forEach((k, v) -> {
                if (v instanceof List) {

                    if (((List<?>) v).size() > (maxNumber - minNumber + 1) - excludeNumberMap.size()) {
                        throw new IndexOutOfBoundsException("excludeNumberMap key " + k + " value size " + ((List<?>) v).size() + " must be less than or equal to " + ((maxNumber - minNumber + 1) - excludeNumberMap.size()) + " (needList.size(): " + (maxNumber - minNumber + 1) + " - excludeNumberMap.size(): " + excludeNumberMap.size() + ")");
                    }

//                    if (requestNumber != 0) {
//                        if (((List<?>) v).size() >= requestNumber) {
//                            throw new IndexOutOfBoundsException("excludeNumberMap key " + k + " value size " + ((List<?>) v).size() + " must be less than or equal to requestNumber " + requestNumber);
//                        }
//                    }


                    ((List) v).forEach(v2 -> {
                        if (numbers.get(k).equals(v2)) {
                            flag.set(true);
                        }
                    });
                }
                if (v instanceof Integer) {
                    if (numbers.get(k).equals(v)) {
                        flag.set(true);
                    }
                }

            });
            if (flag.get()) {
                shuffle(numbers);
            }
        }

    }


    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
//        autoNums();
//        OneNineNot2();
//        OneToEightNotOneToEight();
//        threeToNine();
//        threeToNineGetTwo();
        threeToNineGetTwoExclude4To8();
        long endTime = System.currentTimeMillis();
        System.out.println("执行时间：" + (endTime - startTime));
    }

    /**
     * 生成1-10随机排列组合
     */
    public static void autoNums() {
        System.out.println("生成1-10随机排列组合");
        System.out.println(JSONObject.toJSONString(RandomNumberGenerator.generateLuckyNumbers(1, 10)));
    }

    /**
     * 1-9位都不为2,10位不能为10
     */
    public static void OneNineNot2() {
        System.out.println("1-9位都不为2,10位不能为10");
        Map<Integer, Object> excludeNumMap = new HashMap<>();
        excludeNumMap.put(0, 2);
        excludeNumMap.put(1, 2);
        excludeNumMap.put(2, 2);
        excludeNumMap.put(3, 2);
        excludeNumMap.put(4, 2);
        excludeNumMap.put(5, 2);
        excludeNumMap.put(6, 2);
        excludeNumMap.put(7, 2);
        excludeNumMap.put(8, 2);
        excludeNumMap.put(9, 10);
        System.out.println(JSONObject.toJSONString(RandomNumberGenerator.generateLuckyNumbers(1, 10, excludeNumMap)));
    }

    /**
     * 1-10排列
     * 1-8位都不为1-8
     */
    public static void OneToEightNotOneToEight() {
        System.out.println("1-8位都不为3-4");
        List<Integer> excludeNums = new ArrayList<>();
        excludeNums.add(3);
        excludeNums.add(4);
        Map<Integer, Object> excludeNumMap = new HashMap<>();
        excludeNumMap.put(0, excludeNums);
        excludeNumMap.put(1, excludeNums);
        excludeNumMap.put(2, excludeNums);
        excludeNumMap.put(3, excludeNums);
        excludeNumMap.put(4, excludeNums);
        excludeNumMap.put(5, excludeNums);
        excludeNumMap.put(6, excludeNums);
        excludeNumMap.put(7, excludeNums);
        System.out.println(JSONObject.toJSONString(RandomNumberGenerator.generateLuckyNumbers(1, 10, excludeNumMap)));
    }

    /**
     * 范围生成 3-9的随机排列组合
     */
    public static void threeToNine() {
        System.out.println("3-9随机排列");
        System.out.println(JSONObject.toJSONString(RandomNumberGenerator.generateLuckyNumbers(3, 9)));
    }

    /**
     * 范围取值，生成 3-9的随机排列组合，取2个
     */
    public static void threeToNineGetTwo() {
        System.out.println("生成 3-9的随机排列组合，取2个");
        System.out.println(JSONObject.toJSONString(RandomNumberGenerator.generateLuckyNumbers(3, 9, 2)));
    }

    /**
     * 范围取值，生成 3-9的随机排列组合，取2个,排除4，5，6，7，8 返回应该只有3，9
     */
    public static void threeToNineGetTwoExclude4To8() {
        System.out.println("生成 3-9的随机排列组合，取2个,第一位排除4，5，6，7，8 返回应该只有9,*");
        List<Integer> excludeNums = new ArrayList<>();
        excludeNums.add(4);
        excludeNums.add(5);
        excludeNums.add(6);
        excludeNums.add(7);
        excludeNums.add(8);
        excludeNums.add(3);
        Map<Integer, Object> excludeNumMap = new HashMap<>();
        excludeNumMap.put(0, excludeNums);
//        excludeNumMap.put(1, excludeNums);
        //todo 存在某些数据请求问题比如3-9，取两个，4，5，6，7，8排除，待优化
        System.out.println(JSONObject.toJSONString(RandomNumberGenerator.generateLuckyNumbers(3, 9, 2, excludeNumMap)));
    }
}
